import { useFetch } from "nuxt/app"
import type { UseFetchOptions } from "nuxt/app"

// 通用响应类型
interface Result<T> {
  code: number
  data: T
  message: string
}

// Get 请求参数类型
interface GetOpts {
  url: string
  params?: any
}

// Post 请求参数类型
interface PostOpts {
  url: string
  body?: any
  contentType?: string
  uniqueKey?: string
}

/**
 * 请求函数（useFetch）
 *
 * @param url 路径
 * @param options 配置
 * @param contentType 请求内容类型
 * @param uniqueKey 唯一标识
 */
function _useFetch<T>(
  url: string,
  options: UseFetchOptions<Result<T>>,
  contentType: string = "application/json; charset=utf-8",
  uniqueKey: string = url
): Promise<Result<T>> {
  const runtimeConfig = useRuntimeConfig()
  const baseURL =
    process.env.NODE_ENV === "production" ? runtimeConfig.public.BASE_URL_PROD : runtimeConfig.public.BASE_URL_ENV
  console.log(baseURL)

  const headers: { [key: string]: any } = { ...options.headers }
  if (contentType) {
    headers["content-type"] = contentType
  }

  return new Promise((resolve, reject) => {
    return useFetch<Result<T>>(url, {
      baseURL: baseURL,
      key: uniqueKey,
      timeout: 10000,
      ...options,
      onRequest({ request, options }) {
        // Set the request headers
        const token = useCookie("token")
        if (token.value) {
          headers["Authorization"] = `Bearer ${token.value}`
        }

        options.headers = { ...options.headers, ...headers }
      },
      onRequestError({ request, options, error }) {
        // Handle the request errors
      },
      onResponse({ request, response, options }) {
        // Process the response data
      },
      onResponseError({ request, response, options }) {
        // Handle the response errors
      }
    })
      .then(({ data, error }) => {
        if (!data || error?.value) {
          return reject(error?.value)
        }

        const dataRes = data.value

        if (!dataRes) {
          return reject(dataRes)
        }

        if (dataRes.code !== 0) {
          return reject(dataRes.message)
        }

        return resolve(dataRes)
      })
      .catch((err) => {
        console.log(`[url]:${url}`, `[error]:${err}`)
      })
  })
}

/**
 * 请求函数（$fetch）
 *
 * @param url 路径
 * @param options 配置
 * @param contentType 请求内容类型
 */
function _fetch<T>(
  url: string,
  options: { [key: string]: any },
  contentType: string = "application/json; charset=utf-8"
): Promise<Result<T>> {
  const runtimeConfig = useRuntimeConfig()
  const baseURL =
    process.env.NODE_ENV === "production" ? runtimeConfig.public.BASE_URL_PROD : runtimeConfig.public.BASE_URL_ENV
  console.log(baseURL)

  const headers: { [key: string]: any } = { ...options.headers }
  if (contentType) {
    headers["content-type"] = contentType
  }

  return new Promise((resolve, reject) => {
    return $fetch<Result<T>>(url, {
      baseURL: baseURL,
      timeout: 10000,
      ...options,
      onRequest({ request, options }) {
        // Set the request headers
        const token = useCookie("token")
        if (token.value) {
          headers["Authorization"] = `Bearer ${token.value}`
        }

        options.headers = { ...options.headers, ...headers }
      },
      onRequestError({ request, options, error }) {
        // Handle the request errors
      },
      onResponse({ request, response, options }) {
        // Process the response data
      },
      onResponseError({ request, response, options }) {
        // Handle the response errors
      }
    })
      .then((data) => {
        if (!data) {
          return reject(data)
        }

        if (data.code !== 0) {
          return reject(data.message)
        }

        return resolve(data)
      })
      .catch((err) => {
        console.log(`[url]:${url}`, `[error]:${err}`)
      })
  })
}

function get<T>(opts: GetOpts): Promise<Result<T>> {
  return _useFetch<T>(opts.url, { method: "get", params: opts.params })
}

function post<T>(opts: PostOpts): Promise<Result<T>> {
  return _useFetch<T>(opts.url, { method: "post", body: opts.body }, opts.contentType, opts.uniqueKey)
}

function $get<T>(opts: GetOpts): Promise<Result<T>> {
  return _fetch<T>(opts.url, { method: "get", params: opts.params })
}

function $post<T>(opts: PostOpts): Promise<Result<T>> {
  return _fetch<T>(opts.url, { method: "post", body: opts.body }, opts.contentType)
}

export { get, post, $get, $post }
